home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / os2 / bind493a.zip / named / ns_validate.c < prev    next >
C/C++ Source or Header  |  1995-12-08  |  32KB  |  1,246 lines

  1. /**************************************************************************
  2.  * ns_validate.c (was security.c in original ISI contribution)
  3.  * author: anant kumar
  4.  * contributed: March 17, 1993
  5.  *
  6.  * implements validation procedure for RR's received from a server as a
  7.  * response to a query.
  8.  */
  9.  
  10. #include <sys/param.h>
  11. #include <sys/socket.h>
  12. #include <sys/file.h>
  13.  
  14. #include <netinet/in.h>
  15. #include <arpa/nameser.h>
  16. #include <arpa/inet.h>
  17.  
  18. #include <syslog.h>
  19. #include <errno.h>
  20. #include <stdio.h>
  21. #include <resolv.h>
  22.  
  23. #include "named.h"
  24.  
  25. #ifdef VALIDATE
  26.  
  27. static int        isvalid __P((struct namebuf *, int, int, char *, int)),
  28.             check_addr_ns __P((struct databuf **,
  29.                        struct sockaddr_in *,
  30.                        char *)),
  31.             check_in_tables __P((struct databuf **,
  32.                          struct sockaddr_in *,
  33.                          char *));
  34. #if 0
  35. static void        stick_in_queue __P((char *, int, int, char *));
  36. #endif
  37.  
  38. static NAMEADDR        nameaddrlist[MAXNAMECACHE];
  39. static int        firstNA = 0,
  40.             lastNA = 0;
  41.  
  42. static TO_Validate    *validateQ, *currentVQ;
  43. static int        VQcount;
  44.  
  45. /*****************************************************************
  46.  * validate() is called from dovalidate(). it takes as parameters, 
  47.  * the domain name sought, the class, type etc. of record, the server
  48.  * that gave us the answer and the data it gave us
  49.  *
  50.  * it returns VALID if it is able to validate the record, INVALID if it cannot.
  51.  * furtehr VALID is split into VALID_CACHE if we need to cache this record
  52.  * since the domainname is not something we are authoritative for and
  53.  * VALID_NO_CACHE if the name is something we are authoritative for.
  54.  *
  55.  * pseudocode for function validate is as follows:
  56.  * validate(domain, qdomain, server, type, class, data, dlen, rcode) {
  57.  *
  58.  *       if (dname or a higher level name not found in cache)
  59.  *          return INVALID;
  60.  *       if (NS records for "domain" found in cache){
  61.  *
  62.  *           if (we are authoritative)  /findns() returned NXDOMAIN;/
  63.  *              if (we did not have an exact match on names)
  64.  *                 =>the name does not exist in our database
  65.  *                 => data is bad: return INVALID
  66.  *              if (data agrees with what we have)
  67.  *                return VALID_NO_CACHE;
  68.  *              else return INVALID;
  69.  *    
  70.  *          if (we are not authoritative) /findns() returned OK;/       
  71.  *        if (domain lives below the qdomain)
  72.  *        return VALID_CACHE;
  73.  *          if (address records for NS's found in cache){
  74.  *                       if ("server" = one of the addresses){
  75.  *                               return VALID_CACHE;
  76.  *                       }else{
  77.  *                          stick in queue of "to_validate" data;
  78.  *                          return (INVALID);
  79.  *                       }
  80.  *          else return INVALID;
  81.  *
  82.  * This performs the validation procedure described above. Checks
  83.  * for the longest component of the dname that has a NS record
  84.  * associated with it. At any stage, if no data is found, it implies
  85.  * that the name is bad (has an unknown domain identifier) thus, we
  86.  * return INVALID.
  87.  * If address of one of these servers matches the address of the server
  88.  * that returned us this data, we are happy!
  89.  *
  90.  * since findns will set needs_prime_cache if np = NULL is passed, we always
  91.  * reset it. will let ns_req do it when we are searching for ns records to
  92.  * query someone. hence in all the three cases of switch(findns())
  93.  *                                 we have needs_prime_cache = 0;
  94.  *****************************************************************************/
  95. int
  96. validate(dname, qdomain, server, type, class, data, dlen
  97. #ifdef NCACHE
  98.      ,rcode
  99. #endif
  100.      )
  101.     char *dname, *qdomain;
  102.     struct sockaddr_in *server;
  103.     int type, class;
  104.     char *data;
  105.     int dlen;
  106. #ifdef NCACHE
  107.     int rcode;
  108. #endif
  109. {
  110.     struct namebuf *np, *dnamep;
  111.     struct hashbuf *htp;
  112.     struct databuf *nsp[NSMAX];
  113.     int count;
  114.     const char *fname;
  115.     int exactmatch = 0;
  116.     struct fwdinfo *fwd;
  117.  
  118. #ifdef    DATUMREFCNT
  119.     nsp[0] = NULL;
  120. #endif
  121.     dprintf(3, (ddt,
  122.             "validate(), d:%s, s:[%s], t:%d, c:%d\n",
  123.             dname, inet_ntoa(server->sin_addr), type, class));
  124.  
  125.     /* everything from forwarders is the GOSPEL */
  126.     for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) {
  127.         if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr)
  128.             return (VALID_CACHE);
  129.     }
  130.  
  131.     htp = hashtab;
  132.     if (priming && (dname[0] == '\0'))
  133.         np = NULL;
  134.     else
  135.         np = nlookup(dname, &htp, &fname, 0);
  136.     
  137.     /* we were able to locate namebufs for this domain, or a parent domain,
  138.      * or ??? */
  139.  
  140.     if (np == NULL)
  141.         fname = "";
  142.     dprintf(5, (ddt,
  143.             "validate:namebuf found np:%#lx, d:\"%s\", f:\"%s\"\n",
  144.             (u_long)np, dname, fname));
  145.     /* save the namebuf if we were able to locate the exact dname */
  146.     if (!strcasecmp(dname, fname)) {
  147.         dnamep = np;
  148.         exactmatch = 1;
  149.     }
  150.     switch (findns(&np, class, nsp, &count, 0)) {
  151.     case NXDOMAIN:
  152.         /** we are authoritative for this domain, lookup name 
  153.          * in our zone data, if it matches, return valid.
  154.          * in either case, do not cache
  155.          **/
  156.         dprintf(5, (ddt, "validate: auth data found\n"));
  157. #ifdef    DATUMREFCNT
  158.         free_nsp(nsp);
  159. #endif
  160.         if (needs_prime_cache)
  161.             needs_prime_cache = 0;
  162.  
  163. #ifdef NCACHE
  164.         if (rcode == NXDOMAIN) {
  165.             /* If we had an exactmatch on the name, we found the
  166.              * name in our authority database, so this couldn't 
  167.              * have been a bad name. INVALID data, say so
  168.              */
  169.             if (exactmatch)
  170.                 return (INVALID);
  171.             else
  172.                 /* we did not have an exactmatch, the data is
  173.                  * good, we do not NCACHE stuff we are
  174.                  * authoritative for, though.
  175.                  */
  176.                 return (VALID_NO_CACHE);
  177.         }
  178. #endif
  179.         if (!strcasecmp(dname, np->n_dname)) {
  180.       
  181.             /* if the name we seek is the same as that we have ns
  182.              * records for, compare the data we have to see if it
  183.              * matches. if it does, return valid_no_cache, if it
  184.              * doesn't, invalid.
  185.              */
  186.             if (isvalid(np, type, class, data, dlen))
  187.                 return (VALID_NO_CACHE);
  188.             else
  189.                 return (INVALID);
  190.         }
  191.     
  192.         /* we found ns records in a higher level, if we were unable to
  193.          * locate the exact name earlier, it means we are
  194.          * authoritative for this domain but do not have records for
  195.          * this name. this name is obviously invalid
  196.          */
  197.         if (!exactmatch)
  198.             return (INVALID);
  199.     
  200.         /* we found the exact name earlier and we are obviously
  201.          * authoritative so check for data records and see if any
  202.          * match.
  203.          */
  204.         if (isvalid(dnamep, type, class, data, dlen))
  205.             return (VALID_NO_CACHE);
  206.         else
  207.             return (INVALID);
  208.   
  209.     case SERVFAIL:/* could not find name server records*/
  210.         /* stick_in_queue(dname, type, class, data); */
  211.         if (needs_prime_cache)
  212.             needs_prime_cache = 0;
  213. #ifdef    DATUMREFCNT
  214.         free_nsp(nsp);
  215. #endif
  216.         return (INVALID);
  217.     
  218.     case OK: /*proceed */
  219.         dprintf(5, (ddt, "validate:found ns records\n"));
  220.         if (needs_prime_cache)
  221.             needs_prime_cache = 0;
  222.         if (samedomain(dname, qdomain) ||
  223.             check_addr_ns(nsp, server, dname)) {
  224. #ifdef    DATUMREFCNT
  225.             free_nsp(nsp);
  226. #endif
  227.             return (VALID_CACHE);
  228.         }
  229.         /* server is not one of those we know of */
  230.         /* stick_in_queue(dname, type, class, data); */
  231. #ifdef    DATUMREFCNT
  232.         free_nsp(nsp);
  233. #endif
  234.         return (INVALID);
  235.     default:
  236. #ifdef    DATUMREFCNT
  237.         free_nsp(nsp);
  238. #endif
  239.         return (INVALID);
  240.     } /*switch*/
  241.  
  242. } /*validate*/
  243.  
  244. /***********************************************************************
  245.  * validate rr returned by somebody against your own database, if you are 
  246.  * authoritative for the information. if you have a record that matches,
  247.  * return 1, else return 0. validate() above will use this and determine
  248.  * if the record should be returned/discarded.
  249.  ***********************************************************************/
  250. static int
  251. isvalid(np, type, class, data, dlen)
  252.     struct namebuf *np;
  253.     int type, class;
  254.     char *data;
  255.     int dlen;
  256. {
  257.     register struct databuf *dp;
  258.   
  259.     for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  260.         if (!wanted(dp, class, type)) {
  261.             if ((type == T_CNAME) && (class == dp->d_class)) { 
  262.                 /* if a cname exists, any other will not */
  263.                 return (0);
  264.                 /* we come here only for zone info,
  265.                  * so -ve $ed info can't be
  266.                  */
  267.             }
  268.             continue;
  269.         }
  270.         /* type and class match, if i get here 
  271.          * let's now compare the data section, per RR type
  272.          */  
  273.  
  274.         /* unless, of co